9e5062
@@ -25,10 +25,12 @@
import org.bson.types.ObjectId;
 import org.springframework.core.convert.ConversionException;
 import org.springframework.core.convert.ConversionService;
 import org.springframework.data.mapping.PersistentEntity;
+import org.springframework.data.mapping.context.MappingContext;
 import org.springframework.data.mongodb.core.mapping.MongoPersistentEntity;
 import org.springframework.data.mongodb.core.mapping.MongoPersistentProperty;
 import org.springframework.util.Assert;
 
+import com.mongodb.BasicDBList;
 import com.mongodb.BasicDBObject;
 import com.mongodb.DBObject;
 
@@ -40,6 +42,9 @@
import com.mongodb.DBObject;
  */
 public class QueryMapper {
 
+	private static final List<String> DEFAULT_ID_NAMES = Arrays.asList("id", "_id");
+	private static final String N_OR_PATTERN = "\\$.*or";
+
 	private final ConversionService conversionService;
 	private final MongoConverter converter;
 
@@ -58,8 +63,8 @@
public class QueryMapper {
 	 * Replaces the property keys used in the given {@link DBObject} with the appropriate keys by using the
 	 * {@link PersistentEntity} metadata.
 	 * 
-	 * @param query
-	 * @param entity
+	 * @param query must not be {@literal null}.
+	 * @param entity can be {@literal null}.
 	 * @return
 	 */
 	public DBObject getMappedObject(DBObject query, MongoPersistentEntity<?> entity) {
@@ -67,8 +72,11 @@
public class QueryMapper {
 		DBObject newDbo = new BasicDBObject();
 
 		for (String key : query.keySet()) {
+
+			MongoPersistentEntity<?> nestedEntity = getNestedEntity(entity, key);
 			String newKey = key;
 			Object value = query.get(key);
+
 			if (isIdKey(key, entity)) {
 				if (value instanceof DBObject) {
 					DBObject valueDbo = (DBObject) value;
@@ -80,34 +88,51 @@
public class QueryMapper {
 						}
 						valueDbo.put(inKey, ids.toArray(new Object[ids.size()]));
 					} else {
-						value = getMappedObject((DBObject) value, entity);
+						value = getMappedObject((DBObject) value, nestedEntity);
 					}
 				} else {
 					value = convertId(value);
 				}
 				newKey = "_id";
-			} else if (key.startsWith("$") && key.endsWith("or")) {
+			} else if (key.matches(N_OR_PATTERN)) {
 				// $or/$nor
 				Iterable<?> conditions = (Iterable<?>) value;
 				BasicBSONList newConditions = new BasicBSONList();
 				Iterator<?> iter = conditions.iterator();
 				while (iter.hasNext()) {
-					newConditions.add(getMappedObject((DBObject) iter.next(), entity));
+					newConditions.add(getMappedObject((DBObject) iter.next(), nestedEntity));
 				}
 				value = newConditions;
 			} else if (key.equals("$ne")) {
 				value = convertId(value);
-			} else if (value instanceof DBObject) {
-				newDbo.put(newKey, getMappedObject((DBObject) value, entity));
-				continue;
 			}
 
-			newDbo.put(newKey, converter.convertToMongoType(value));
+			newDbo.put(newKey, convertSimpleOrDBObject(value, nestedEntity));
 		}
 
 		return newDbo;
 	}
 
+	/**
+	 * Retriggers mapping if the given source is a {@link DBObject} or simply invokes the
+	 * 
+	 * @param source
+	 * @param entity
+	 * @return
+	 */
+	private Object convertSimpleOrDBObject(Object source, MongoPersistentEntity<?> entity) {
+
+		if (source instanceof BasicDBList) {
+			return converter.convertToMongoType(source);
+		}
+
+		if (source instanceof DBObject) {
+			return getMappedObject((DBObject) source, entity);
+		}
+
+		return converter.convertToMongoType(source);
+	}
+
 	/**
 	 * Returns whether the given key will be considered an id key.
 	 * 
@@ -122,7 +147,19 @@
public class QueryMapper {
 			return idProperty.getName().equals(key) || idProperty.getFieldName().equals(key);
 		}
 
-		return Arrays.asList("id", "_id").contains(key);
+		return DEFAULT_ID_NAMES.contains(key);
+	}
+
+	private MongoPersistentEntity<?> getNestedEntity(MongoPersistentEntity<?> entity, String key) {
+
+		MongoPersistentProperty property = entity == null ? null : entity.getPersistentProperty(key);
+
+		if (property == null || !property.isEntity()) {
+			return null;
+		}
+
+		MappingContext<? extends MongoPersistentEntity<?>, MongoPersistentProperty> context = converter.getMappingContext();
+		return context.getPersistentEntity(property);
 	}
 
 	/**
